1 Introduction

En 2021 à Taiwan, le nombre d’entreprises déclarées en faillite est en moyenne de 2400 par mois. La faillite des entreprises présente des enjeux d’envergure particulièrement durant la crise de la Covid-19, où de nombreuses entreprises à travers le monde se sont retrouvées en difficultés dans l’exercice de leurs activités. Nous observons aussi une hausse des prêts garantis par les États dans certains pays, afin de contenir les effets de la crise sur le financement des entreprises. Ainsi il serait crucial de trouver la méthodologie adéquate afin de pouvoir prédire les faillites d’entreprises dans l’optique de pouvoir estimer les besoins de chacune en matière d’aides et de financement.

Plusieurs travaux montrent que la faillite d’une entreprise est le fruit de difficultés financières mesurables par un large panel d’indicateurs. Ainsi, notre étude consistera à déterminer plusieurs modèles prédictifs sur la base d’indicateurs financiers de l’entreprise. Nous évaluerons par la suite la précision prédictive de chacun des modèles et nous comparerons les performances des meilleures spécifications.

Les données que nous utiliserons proviennent du Taiwan Economic Journal. Elles couvrent la période 1999-2009 et concernent des entreprises taïwanaises. La base de données compte alors 6819 observations ainsi que 95 variables, l’unité d’observation étant les entreprises.

L’étude de la prédiction des faillites d’entreprises a déjà été traité plusieurs fois. Les articles traitant de ce sujet, utilisent de multiples méthodes d’apprentissage automatique. Notre projet se basera sur la comparaison de plusieurs modèles de classification en tentant d’y ajouter des approches qui n’ont pas été traitées jusqu’à maintenant. Nous nous inspirerons également des modèles déjà effectués tout en essayant de les approfondir. De plus, nous tenterons d’aborder le choix des variables et leur traitement de manière différente.

Notre étude s’articulera en cinq parties :

    1. Premièrement, nous présenterons une brève revue de littérature relative à notre problématique;
    1. La deuxième partie sera consacrée au nettoyage de notre base de données, à la présentation des variables qui la composent et à une analyse statistique descriptives de nos prédicteurs;
    1. Ensuite, dans la mesure où nous faisons face à une grande hétérogeineité des fréquences pour notre variable à prédire et donc à un déséquilibre des classes (ou Class Imbalance), dans cette partie, nous utiliserons des méthodes d’apprentissage sensibles aux coûts (ou cost-sensitive learning) étant une approche courante pour résoudre ce problème;
    1. Dans la troisème partie, nous utiliserons plusieurs modèles prédictifs et nous justifierons leur utilisation;
    1. Enfin, nous comparerons les performances de nos modèles respectifs et nous ferons un choix concernant les meilleures spécifications.

2 Revue de la littérature existante

Les travaux étudiant la prédiction de la faillite des entreprises sont nombreux et ont commencé à voir le jour dès les années 1930. Les précurseurs de cette question cruciale ont publiés une étude parue dans un rapport du Bureau of Business Research(1930), questionnant sur les déterminants de la défaillance des entreprises. L’échantillon de l’étude comportait 29 entreprises industrielles et consistait à comparer la valeur de 24 ratios financiers à la moyenne de l’échantillon et d’en tirer des conclusions quant aux caractéristiques similaires des entreprises défaillantes. Sans vouloir offenser ses utilisateurs, cette méthode d’évaluation univariée est bien évidement caduque et comporte un nombre important de biais.

D’autres études multivariées publiées dans les années 1960 à 1970 utilisaient principalement l’Analyse discrimante. Dans les années 1980 à 1990 l’Analyse Logit et les Réseaux Neuronaux étaient les méthodes d’évaluation prédominantes (voir Bellovary (2007) pour un résumé historique de la prédiction de la faillite).

Des études plus récentes utilisant non seulement d’autres méthodes statistiques mais également des échantillons plus large sont plus adaptées à notre problématique. Wu (2010) utilise des données de sociétés cotées au New York Stock Exchange et à l’American Express Company couvrant la période 1980 à 2006. Cinq modèles sont utilisés et comparés : Analyse discriminante multiple, Logit, Probit, Hazard model, Black-Scholes model et enfin un modèle logit multi-période. Les auteurs en arrivent à la conclusion que le Hazard model emprunté à Shumway (2001) surpasse en terme de performance prédictive les autres modèles. Les variables explicatives fournissant les prévisions les plus fiables sur les faillites d’entreprises sont relatives à des informations comptables, des données de marché et des caractéristiques de la société.

Pervan et al. (2011), utilisent des données de 156 entreprises en Croatie pour la période Janvier-Juin 2010 et des ratio financiers comme variables explicatives. Les entreprises étudiées sont plutôt hétérogènes. En effet, les secteurs industriels sélectionnés comprennent des entreprises opérant dans le secteur manufacturier et le commerce de gros. Les entreprises saines et en faillite sont du même nombre et sont sélectionnées de manière aléatoire. Les auteurs utilisent deux modèles : Régression logistique et Analyse discriminante. Le modèle d’Analyse discriminante a la précision la plus modeste dans la prédiction des entreprises en faillite, en effet, elle est de 79,5 % contre 85.9 % pour le modèle de Régression logistique.

Mu-Yen Chen (2011), utilise une base de données comportant 200 sociétés cotées à la Taiwan Stock Exchange Corporation. L’auteur utilise et compare 9 modèles différents avec des méthodes relatives à la classification par arbre de décision, aux réseaux neuronaux et aux techniques de calcul évolutif. Son modèle le plus performant en terme de prédiction est le PSO-SVM (Particle Swarm Optimization-Support Vector Machine). L’utilisation d’une Analyse en composante principale a permis de déterminer les variables appropriées à l’étude parmi 42 ratios, dont 33 financiers, 8 non financiers et 1 indice macroéconomique. Seuls 8 des 42 ratios ont été gardées après l’analyse en composante principale et toutes étaient des ratios financiers. L’auteur en conclu donc que les ratios financiers ont un effet plus important sur la performance de la prédiction financière que les ratios non financiers et les indices macroéconomiques.

Finalement, Deron Liang et al. (2016) utilisent la même base de données que celle de notre étude. Pour sélectionner les variables ils utilisent cinq méthodes : Analyse discriminante par étapes, la régression logistique par étapes, le test t, l’algorithme génétique et l’élimination récursive. Ils en concluent que la combinaison de ratios financiers et d’indicateurs de gouvernance d’entreprise sont plus adaptés que l’utilisation exclusive de ratios financiers pour prédire la faillite des entreprises. Leur modèles les plus performants sont : stepwise discriminant analysis (SDA) et support vector machine.

Les études se penchant sur cette problématique utilisent des données de nature différentes (type d’entreprises, variables explicatives, période etc.) , et la divergence de leurs conclusions relatives aux modèles les plus performant dans la prédiction de la faillite d’entreprises suggère que certaines modélisations semblent être plus adaptées en fonction des données à disposition.

3 Données

df <- read_csv("C:/Users/33666/Desktop/M2/Projet_stat/data.csv")
The working directory was changed to C:/Users/33666/Documents inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.

BLABLABLA

3.1 Vérifications des données

# Nombre total de valeurs manquantes
sum(is.na(df))
[1] 0
#Nombre total de duplicats
sum(duplicated(df))
[1] 0
dim(df)
[1] 6819   96

3.2 Variable d’interêt

names(df)[names(df) == "Bankrupt?"] <- 'bk'
df$bk <- as.factor(df$bk)
df$bk <- relevel(df$bk, ref = 1)
datasummary_skim(df, type = "categorical", output = "kableExtra")
bk N %
0 6599 96.8
1 220 3.2
pct_format = scales::percent_format(accuracy = .1)
p <- ggplot(df, aes(x = bk, fill = bk)) +
  geom_bar() +
  geom_text(
    aes(
      label = sprintf(
        '%d (%s)',
        ..count..,
        pct_format(..count.. / sum(..count..))
      )
    ),
    stat = 'count',
    nudge_y = .2,
    colour = 'Dark blue',
    size = 5)
 
p

3.3 Predicteurs

Les variables exogènes ont d’abord été normalisées par la méthode dites du “feature scaling” : \[ F(x_i) = \frac{x_i \space- \space min(x)}{ max(x) \space - \space min(x)}\]

De ce fait les ###PK CA A ETE NORMALIZE ? ####

3.3.1 Statistiques descritptives

table1 <- psych::describe(df, skew = F, ranges=F)

table1 %>%
  kbl(caption = "Recreating booktabs style table") %>%
  kable_classic(full_width = F, html_font = "Cambria")
Recreating booktabs style table
vars n mean sd se
bk* 1 6819 1.032263e+00 1.767102e-01 2.139900e-03
ROA(C) before interest and depreciation before interest 2 6819 5.051796e-01 6.068560e-02 7.349000e-04
ROA(A) before interest and % after tax 3 6819 5.586249e-01 6.562000e-02 7.947000e-04
ROA(B) before interest and depreciation after tax 4 6819 5.535887e-01 6.159480e-02 7.459000e-04
Operating Gross Margin 5 6819 6.079480e-01 1.693380e-02 2.051000e-04
Realized Sales Gross Margin 6 6819 6.079295e-01 1.691610e-02 2.049000e-04
Operating Profit Rate 7 6819 9.987551e-01 1.301000e-02 1.575000e-04
Pre-tax net Interest Rate 8 6819 7.971898e-01 1.286900e-02 1.558000e-04
After-tax net Interest Rate 9 6819 8.090836e-01 1.360070e-02 1.647000e-04
Non-industry income and expenditure/revenue 10 6819 3.036229e-01 1.116340e-02 1.352000e-04
Continuous interest rate (after tax) 11 6819 7.813814e-01 1.267900e-02 1.535000e-04
Operating Expense Rate 12 6819 1.995347e+09 3.237684e+09 3.920795e+07
Research and development expense rate 13 6819 1.950427e+09 2.598292e+09 3.146499e+07
Cash flow rate 14 6819 4.674312e-01 1.703550e-02 2.063000e-04
Interest-bearing debt interest rate 15 6819 1.644801e+07 1.082750e+08 1.311197e+06
Tax rate (A) 16 6819 1.150007e-01 1.386675e-01 1.679200e-03
Net Value Per Share (B) 17 6819 1.906606e-01 3.338980e-02 4.043000e-04
Net Value Per Share (A) 18 6819 1.906332e-01 3.347350e-02 4.054000e-04
Net Value Per Share (C) 19 6819 1.906724e-01 3.348010e-02 4.054000e-04
Persistent EPS in the Last Four Seasons 20 6819 2.288129e-01 3.326260e-02 4.028000e-04
Cash Flow Per Share 21 6819 3.234819e-01 1.761090e-02 2.133000e-04
Revenue Per Share (Yuan ¥) 22 6819 1.328641e+06 5.170709e+07 6.261664e+05
Operating Profit Per Share (Yuan ¥) 23 6819 1.090907e-01 2.794220e-02 3.384000e-04
Per Share Net profit before tax (Yuan) 24 6819 1.843606e-01 3.318020e-02 4.018000e-04
Realized Sales Gross Profit Growth Rate 25 6819 2.240790e-02 1.207930e-02 1.463000e-04
Operating Profit Growth Rate 26 6819 8.479800e-01 1.075250e-02 1.302000e-04
After-tax Net Profit Growth Rate 27 6819 6.891461e-01 1.385300e-02 1.678000e-04
Regular Net Profit Growth Rate 28 6819 6.891500e-01 1.391030e-02 1.685000e-04
Continuous Net Profit Growth Rate 29 6819 2.176390e-01 1.006300e-02 1.219000e-04
Total Asset Growth Rate 30 6819 5.508097e+09 2.897718e+09 3.509100e+07
Net Value Growth Rate 31 6819 1.566212e+06 1.141594e+08 1.382456e+06
Total Asset Return Growth Rate Ratio 32 6819 2.642475e-01 9.634200e-03 1.167000e-04
Cash Reinvestment % 33 6819 3.796767e-01 2.073660e-02 2.511000e-04
Current Ratio 34 6819 4.032850e+05 3.330216e+07 4.032849e+05
Quick Ratio 35 6819 8.376595e+06 2.446847e+08 2.963102e+06
Interest Expense Ratio 36 6819 6.309910e-01 1.123850e-02 1.361000e-04
Total debt/Total net worth 37 6819 4.416337e+06 1.684069e+08 2.039387e+06
Debt ratio % 38 6819 1.131771e-01 5.392030e-02 6.530000e-04
Net worth/Assets 39 6819 8.868229e-01 5.392030e-02 6.530000e-04
Long-term fund suitability ratio (A) 40 6819 8.782700e-03 2.815290e-02 3.409000e-04
Borrowing dependency 41 6819 3.746543e-01 1.628620e-02 1.972000e-04
Contingent liabilities/Net worth 42 6819 5.968300e-03 1.218840e-02 1.476000e-04
Operating profit/Paid-in capital 43 6819 1.089767e-01 2.778170e-02 3.364000e-04
Net profit before tax/Paid-in capital 44 6819 1.827150e-01 3.078480e-02 3.728000e-04
Inventory and accounts receivable/Net value 45 6819 4.024593e-01 1.332410e-02 1.614000e-04
Total Asset Turnover 46 6819 1.416056e-01 1.011450e-01 1.224900e-03
Accounts Receivable Turnover 47 6819 1.278971e+07 2.782598e+08 3.369692e+06
Average Collection Days 48 6819 9.826221e+06 2.563589e+08 3.104474e+06
Inventory Turnover Rate (times) 49 6819 2.149106e+09 3.247967e+09 3.933247e+07
Fixed Assets Turnover Frequency 50 6819 1.008596e+09 2.477557e+09 3.000291e+07
Net Worth Turnover Rate (times) 51 6819 3.859510e-02 3.668030e-02 4.442000e-04
Revenue per person 52 6819 2.325854e+06 1.366327e+08 1.654604e+06
Operating profit per person 53 6819 4.006710e-01 3.272010e-02 3.962000e-04
Allocation rate per person 54 6819 1.125579e+07 2.945063e+08 3.566434e+06
Working Capital to Total Assets 55 6819 8.141252e-01 5.905440e-02 7.151000e-04
Quick Assets/Total Assets 56 6819 4.001318e-01 2.019981e-01 2.446200e-03
Current Assets/Total Assets 57 6819 5.222734e-01 2.181118e-01 2.641300e-03
Cash/Total Assets 58 6819 1.240946e-01 1.392506e-01 1.686300e-03
Quick Assets/Current Liability 59 6819 3.592902e+06 1.716209e+08 2.078308e+06
Cash/Current Liability 60 6819 3.715999e+07 5.103509e+08 6.180286e+06
Current Liability to Assets 61 6819 9.067280e-02 5.028990e-02 6.090000e-04
Operating Funds to Liability 62 6819 3.538280e-01 3.514720e-02 4.256000e-04
Inventory/Working Capital 63 6819 2.773951e-01 1.046880e-02 1.268000e-04
Inventory/Current Liability 64 6819 5.580680e+07 5.820516e+08 7.048571e+06
Current Liabilities/Liability 65 6819 7.615989e-01 2.066768e-01 2.502800e-03
Working Capital/Equity 66 6819 7.358165e-01 1.167800e-02 1.414000e-04
Current Liabilities/Equity 67 6819 3.314098e-01 1.348800e-02 1.633000e-04
Long-term Liability to Current Assets 68 6819 5.416004e+07 5.702706e+08 6.905906e+06
Retained Earnings to Total Assets 69 6819 9.347328e-01 2.556420e-02 3.096000e-04
Total income/Total expense 70 6819 2.548900e-03 1.209280e-02 1.464000e-04
Total expense/Assets 71 6819 2.918410e-02 2.714880e-02 3.288000e-04
Current Asset Turnover Rate 72 6819 1.195856e+09 2.821161e+09 3.416391e+07
Quick Asset Turnover Rate 73 6819 2.163735e+09 3.374944e+09 4.087015e+07
Working capitcal Turnover Rate 74 6819 5.940063e-01 8.959400e-03 1.085000e-04
Cash Turnover Rate 75 6819 2.471977e+09 2.938623e+09 3.558636e+07
Cash Flow to Sales 76 6819 6.715308e-01 9.341300e-03 1.131000e-04
Fixed Assets to Assets 77 6819 1.220121e+06 1.007542e+08 1.220120e+06
Current Liability to Liability 78 6819 7.615989e-01 2.066768e-01 2.502800e-03
Current Liability to Equity 79 6819 3.314098e-01 1.348800e-02 1.633000e-04
Equity to Long-term Liability 80 6819 1.156447e-01 1.952920e-02 2.365000e-04
Cash Flow to Total Assets 81 6819 6.497306e-01 4.737210e-02 5.737000e-04
Cash Flow to Liability 82 6819 4.618493e-01 2.994270e-02 3.626000e-04
CFO to Assets 83 6819 5.934151e-01 5.856060e-02 7.092000e-04
Cash Flow to Equity 84 6819 3.155824e-01 1.296090e-02 1.570000e-04
Current Liability to Current Assets 85 6819 3.150640e-02 3.084470e-02 3.735000e-04
Liability-Assets Flag 86 6819 1.173200e-03 3.423430e-02 4.146000e-04
Net Income to Total Assets 87 6819 8.077602e-01 4.033220e-02 4.884000e-04
Total assets to GNP price 88 6819 1.862942e+07 3.764501e+08 4.558763e+06
No-credit Interval 89 6819 6.239146e-01 1.228950e-02 1.488000e-04
Gross Profit to Sales 90 6819 6.079463e-01 1.693380e-02 2.051000e-04
Net Income to Stockholder's Equity 91 6819 8.404021e-01 1.452250e-02 1.759000e-04
Liability to Equity 92 6819 2.803652e-01 1.446320e-02 1.751000e-04
Degree of Financial Leverage (DFL) 93 6819 2.754110e-02 1.566790e-02 1.897000e-04
Interest Coverage Ratio (Interest expense to EBIT) 94 6819 5.653579e-01 1.321420e-02 1.600000e-04
Net Income Flag 95 6819 1.000000e+00 0.000000e+00 0.000000e+00
Equity to Liability 96 6819 4.757840e-02 5.001370e-02 6.057000e-04

3.3.2 Distribution des prédicteurs

Lorsque nous observons les variables de la dataset -on voit que certaines sont des variantes des autres tel que un ratio avant / apres interet, on en garde un à chaque fois -Il y’a des variables qui se repètent et on les même valeurs distribution (eg: Current Liability to Liability et Liability to Liability) -Certains ratios sont n’ont que de changement leurs dénominateurs

4 Features selection

BLABLA

include_graphics("GRAPH1.drawio.png")

4.1 Selection préliminaire

###Variable inutiles redondantes

colnames(df)
 [1] "bk"                                                     
 [2] "ROA(C) before interest and depreciation before interest"
 [3] "ROA(A) before interest and % after tax"                 
 [4] "ROA(B) before interest and depreciation after tax"      
 [5] "Operating Gross Margin"                                 
 [6] "Realized Sales Gross Margin"                            
 [7] "Operating Profit Rate"                                  
 [8] "Pre-tax net Interest Rate"                              
 [9] "After-tax net Interest Rate"                            
[10] "Non-industry income and expenditure/revenue"            
[11] "Continuous interest rate (after tax)"                   
[12] "Operating Expense Rate"                                 
[13] "Research and development expense rate"                  
[14] "Cash flow rate"                                         
[15] "Interest-bearing debt interest rate"                    
[16] "Tax rate (A)"                                           
[17] "Net Value Per Share (B)"                                
[18] "Net Value Per Share (A)"                                
[19] "Net Value Per Share (C)"                                
[20] "Persistent EPS in the Last Four Seasons"                
[21] "Cash Flow Per Share"                                    
[22] "Revenue Per Share (Yuan ¥)"                             
[23] "Operating Profit Per Share (Yuan ¥)"                    
[24] "Per Share Net profit before tax (Yuan)"                 
[25] "Realized Sales Gross Profit Growth Rate"                
[26] "Operating Profit Growth Rate"                           
[27] "After-tax Net Profit Growth Rate"                       
[28] "Regular Net Profit Growth Rate"                         
[29] "Continuous Net Profit Growth Rate"                      
[30] "Total Asset Growth Rate"                                
[31] "Net Value Growth Rate"                                  
[32] "Total Asset Return Growth Rate Ratio"                   
[33] "Cash Reinvestment %"                                    
[34] "Current Ratio"                                          
[35] "Quick Ratio"                                            
[36] "Interest Expense Ratio"                                 
[37] "Total debt/Total net worth"                             
[38] "Debt ratio %"                                           
[39] "Net worth/Assets"                                       
[40] "Long-term fund suitability ratio (A)"                   
[41] "Borrowing dependency"                                   
[42] "Contingent liabilities/Net worth"                       
[43] "Operating profit/Paid-in capital"                       
[44] "Net profit before tax/Paid-in capital"                  
[45] "Inventory and accounts receivable/Net value"            
[46] "Total Asset Turnover"                                   
[47] "Accounts Receivable Turnover"                           
[48] "Average Collection Days"                                
[49] "Inventory Turnover Rate (times)"                        
[50] "Fixed Assets Turnover Frequency"                        
[51] "Net Worth Turnover Rate (times)"                        
[52] "Revenue per person"                                     
[53] "Operating profit per person"                            
[54] "Allocation rate per person"                             
[55] "Working Capital to Total Assets"                        
[56] "Quick Assets/Total Assets"                              
[57] "Current Assets/Total Assets"                            
[58] "Cash/Total Assets"                                      
[59] "Quick Assets/Current Liability"                         
[60] "Cash/Current Liability"                                 
[61] "Current Liability to Assets"                            
[62] "Operating Funds to Liability"                           
[63] "Inventory/Working Capital"                              
[64] "Inventory/Current Liability"                            
[65] "Current Liabilities/Liability"                          
[66] "Working Capital/Equity"                                 
[67] "Current Liabilities/Equity"                             
[68] "Long-term Liability to Current Assets"                  
[69] "Retained Earnings to Total Assets"                      
[70] "Total income/Total expense"                             
[71] "Total expense/Assets"                                   
[72] "Current Asset Turnover Rate"                            
[73] "Quick Asset Turnover Rate"                              
[74] "Working capitcal Turnover Rate"                         
[75] "Cash Turnover Rate"                                     
[76] "Cash Flow to Sales"                                     
[77] "Fixed Assets to Assets"                                 
[78] "Current Liability to Liability"                         
[79] "Current Liability to Equity"                            
[80] "Equity to Long-term Liability"                          
[81] "Cash Flow to Total Assets"                              
[82] "Cash Flow to Liability"                                 
[83] "CFO to Assets"                                          
[84] "Cash Flow to Equity"                                    
[85] "Current Liability to Current Assets"                    
[86] "Liability-Assets Flag"                                  
[87] "Net Income to Total Assets"                             
[88] "Total assets to GNP price"                              
[89] "No-credit Interval"                                     
[90] "Gross Profit to Sales"                                  
[91] "Net Income to Stockholder's Equity"                     
[92] "Liability to Equity"                                    
[93] "Degree of Financial Leverage (DFL)"                     
[94] "Interest Coverage Ratio (Interest expense to EBIT)"     
[95] "Net Income Flag"                                        
[96] "Equity to Liability"                                    
df[ ,c(4,3,8,18,19,23,79,67,78)] <- list(NULL)

4.1.1 Zero-Variance predictor*

predictors <- df[,-c(1)]
rmp1<-names(predictors)[nearZeroVar(predictors)] # Nous donne les variables ne prenant qu'une seul valeur ou ayant une variance quasi-nulle
print(rmp1)
[1] "Liability-Assets Flag" "Net Income Flag"      
table(predictors$`Net Income Flag`)

   1 
6819 
table(predictors$`Liability-Assets Flag`)

   0    1 
6811    8 
df[ ,c("Liability-Assets Flag", "Net Income Flag")] <- list(NULL)

Nous pouvons d’ores et déja retirer les variables Liability-Assets Flag et Net Income Flag. En effet, la variable Liability-Assets Flag possède une variance très proches de 0, ce qui veut dire qu’elle ne prend pas beacoup de valeurs différentes. Ensuite, concernant Net Income Flag, la variable ne comporte qu’une seule valeur unique égale à 1.

4.1.2 Variance inflation Factor and Correlation ratios

df = pd.read_csv("C:/Users/33666/Desktop/M2/Projet_stat/data.csv")

p = df
p.drop(p.columns[[0,3,2,7,17,18,22,78,66, 94, 85, 77]], axis = 1, inplace=True)

James G, Witten D, Hastie T, Tibshirani R. An Introduction to Statistical Learning: With Applications in R. 1st ed. 2013, Corr. 7th printing 2017 edition. Springer; 2013. –> VIF 10 is problematic

                                         feature           VIF
75                    Net Income to Total Assets  1.147856e+01
69                 Equity to Long-term Liability  1.245814e+01
16        Per Share Net profit before tax (Yuan)  1.974217e+01
13       Persistent EPS in the Last Four Seasons  2.203057e+01
36         Net profit before tax/Paid-in capital  2.311774e+01
67                            Cash Flow to Sales  2.649558e+01
37   Inventory and accounts receivable/Net value  3.269785e+01
33                          Borrowing dependency  3.694166e+01
58                        Working Capital/Equity  3.708076e+01
65                Working capitcal Turnover Rate  8.654667e+01
20                Regular Net Profit Growth Rate  1.325916e+02
19              After-tax Net Profit Growth Rate  1.333995e+02
80                           Liability to Equity  1.373998e+02
5    Non-industry income and expenditure/revenue  2.279432e+02
6           Continuous interest rate (after tax)  3.365468e+02
2                    Realized Sales Gross Margin  1.074951e+03
3                          Operating Profit Rate  1.723033e+03
4                    After-tax net Interest Rate  1.815654e+03
78                         Gross Profit to Sales  1.218257e+07
1                         Operating Gross Margin  4.034741e+07
31                              Net worth/Assets  8.148682e+08
30                                  Debt ratio %  2.160007e+09
49                   Current Assets/Total Assets  3.624503e+09
53                   Current Liability to Assets  6.458329e+09
47               Working Capital to Total Assets  1.183608e+10
df[ ,c('Net Income to Total Assets','Equity to Long-term Liability','Per Share Net profit before tax (Yuan)', 'Persistent EPS in the Last Four Seasons', 'Net profit before tax/Paid-in capital', 'Cash Flow to Sales', 'Inventory and accounts receivable/Net value', 'Borrowing dependency', 'Working Capital/Equity', 'Working capitcal Turnover Rate', 'Regular Net Profit Growth Rate', ' fter-tax Net Profit Growth Rate', 'Liability to Equity', 'Non-industry income and expenditure/revenue', 'Continuous interest rate (after tax)', 'Realized Sales Gross Margin', 'Operating Profit Rate', 'After-tax net Interest Rate', 'Gross Profit to Sales', 'Operating Gross Margin', 'Net worth/Assets', 'Debt ratio %', 'Current Assets/Total Assets', 'Current Liability to Assets', ' orking Capital to Total Assets')] <- list(NULL)

4.1.3 Pertinence des variables

library(DiscriMiner) # La fonction c'est Quanti-Quali
le package 㤼㸱DiscriMiner㤼㸲 a 攼㸹t攼㸹 compil攼㸹 avec la version R 4.1.3Registered S3 method overwritten by 'DiscriMiner':
  method      from 
  print.plsda caret
pred <- colnames(df[,-1])

pred <- as.data.frame(pred)
pred$cor_ratio <- NA

pred=as.matrix(pred)

for (i in 1:61) {
  
    grp=as.factor(df$bk)
    name = as.character(pred[i,1])
    pred[i,2] = as.numeric(corRatio(df[[name]],grp))
    
}

pred=as.data.frame(pred)
pred[order(pred$cor_ratio, decreasing = FALSE),]
NA
lharba <- pred[pred$cor_ratio <= median(pred$cor_ratio), ]
lharba <- as.character(lharba$pred)
print(lharba)
 [1] "Research and development expense rate" "Cash flow rate"                       
 [3] "Interest-bearing debt interest rate"   "Cash Flow Per Share"                  
 [5] "Operating Profit Growth Rate"          "After-tax Net Profit Growth Rate"     
 [7] "Total Asset Growth Rate"               "Net Value Growth Rate"                
 [9] "Total Asset Return Growth Rate Ratio"  "Cash Reinvestment %"                  
[11] "Quick Ratio"                           "Total debt/Total net worth"           
[13] "Long-term fund suitability ratio (A)"  "Contingent liabilities/Net worth"     
[15] "Total Asset Turnover"                  "Fixed Assets Turnover Frequency"      
[17] "Net Worth Turnover Rate (times)"       "Revenue per person"                   
[19] "Cash/Current Liability"                "Operating Funds to Liability"         
[21] "Current Liabilities/Liability"         "Current Asset Turnover Rate"          
[23] "Quick Asset Turnover Rate"             "Cash Turnover Rate"                   
[25] "Fixed Assets to Assets"                "Cash Flow to Total Assets"            
[27] "Cash Flow to Liability"                "Cash Flow to Equity"                  
[29] "Total assets to GNP price"             "Degree of Financial Leverage (DFL)"   
[31] "Equity to Liability"                  
for (col in lharba)
    df[[col]]<-NULL
dim(df)
[1] 6819   31

4.2 SELECTION 1

4.3 APPROCHE PAR COMPOSANTES PRINCIPALES

options(scipen = 999)# In order to disable Scientific Notation

myPr<-prcomp(df[,-1],scale=FALSE) # Creating PCs
summary(myPr)
Importance of components:
                                   PC1             PC2             PC3
Standard deviation     3446078327.6927 3026169807.3978 581357119.11620
Proportion of Variance          0.5408          0.4170         0.01539
Cumulative Proportion           0.5408          0.9578         0.97323
                                   PC4             PC5             PC6
Standard deviation     570224898.99792 294387560.07746 278033268.95322
Proportion of Variance         0.01481         0.00395         0.00352
Cumulative Proportion          0.98804         0.99198         0.99550
                                   PC7             PC8            PC9           PC10
Standard deviation     256338088.89731 171588657.56087 49786465.84299 33299783.49166
Proportion of Variance         0.00299         0.00134        0.00011        0.00005
Cumulative Proportion          0.99850         0.99984        0.99995        1.00000
                         PC11   PC12  PC13    PC14    PC15    PC16    PC17    PC18
Standard deviation     0.2274 0.1394 0.103 0.07082 0.04787 0.04083 0.02987 0.02746
Proportion of Variance 0.0000 0.0000 0.000 0.00000 0.00000 0.00000 0.00000 0.00000
Cumulative Proportion  1.0000 1.0000 1.000 1.00000 1.00000 1.00000 1.00000 1.00000
                          PC19    PC20    PC21    PC22    PC23    PC24    PC25
Standard deviation     0.02585 0.01856 0.01539 0.01408 0.01373 0.01323 0.01226
Proportion of Variance 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
Cumulative Proportion  1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000
                          PC26   PC27    PC28    PC29     PC30
Standard deviation     0.01201 0.0112 0.01049 0.01039 0.009755
Proportion of Variance 0.00000 0.0000 0.00000 0.00000 0.000000
Cumulative Proportion  1.00000 1.0000 1.00000 1.00000 1.000000
plot(myPr)

Loadings <- myPr$rotation # Extracting PCs for regression 

axes <- predict(myPr, newdata = df)
acp_df <- cbind(df[1], axes) # ajout des Pcs dans une nouvelle base de données 
acp_df[,4:31]<-list(NULL)

5 Modélisation

include_graphics("GRAPH2.drawio.png")

NA
library(parallel)
library(doParallel)
Le chargement a n攼㸹cessit攼㸹 le package : foreach

Attachement du package : 㤼㸱foreach㤼㸲

Les objets suivants sont masqu攼㸹s depuis 㤼㸱package:purrr㤼㸲:

    accumulate, when

Le chargement a n攼㸹cessit攼㸹 le package : iterators
# control variables
method <- "boot"
numbers <- 30 # Number of bootstrap samples
bTunes <- 30 # tune number of models
seed <- 777

# Seeds
bSeeds <- bootsetSeeds(method = method, numbers = numbers, tunes = bTunes,
seed = seed)
# Configure the trainControl argument for cross-validation
sixStats <- function(...) c(twoClassSummary(...),
defaultSummary(...), mnLogLoss(...))
bCtrl <- trainControl(method = method, number = numbers,
classProbs = TRUE, savePredictions = TRUE,
seeds = bSeeds, summaryFunction = sixStats,
allowParallel = TRUE)

5.1 PC Models

set.seed(1)
inIndex <- createDataPartition(acp_df$bk, p = .3, list = FALSE, times = 1)
acp_train <- acp_df[inIndex,]
acp_test <- acp_df[-inIndex,]

acp_test$bk<-ifelse(acp_test$bk==1,"Yes","No")

acp_train$bk<-ifelse(acp_train$bk==1,"Yes","No")

5.1.1 Logit models

\(SMOTE\)

library(themis)
bCtrl$sampling <- "smote"
nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
acp_logitsmote <- train(bk ~ ., data = acp_train, method = "glm",
trControl = bCtrl)
stopCluster(cl)
acp_logitsmote$results %>%
  kable(digits=2) %>%
kable_styling(latex_options = "HOLD_position")
parameter ROC Sens Spec Accuracy Kappa logLoss ROCSD SensSD SpecSD AccuracySD KappaSD logLossSD
none 0.46 0.47 0.47 0.47 -0.01 0.69 0.03 0.14 0.18 0.13 0.01 0

5.1.1.1 Rose

bCtrl$sampling <- "rose"

nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
acp_logitrose <- train(bk ~ ., data = acp_train, method = "glm", trControl = bCtrl)
le package 㤼㸱ROSE㤼㸲 a 攼㸹t攼㸹 compil攼㸹 avec la version R 4.1.3Loaded ROSE 0.0-4
stopCluster(cl)
acp_logitrose$results %>%
  kable(digits=2) %>%
  kable_styling(latex_options = "striped")
parameter ROC Sens Spec Accuracy Kappa logLoss ROCSD SensSD SpecSD AccuracySD KappaSD logLossSD
none 0.47 0.54 0.41 0.54 -0.01 0.69 0.04 0.22 0.24 0.2 0.01 0.02

5.1.1.2 Down-sampling

bCtrl$sampling <- "down"
nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
acp_logitdown <- train(bk ~ ., data = acp_train, method = "glm", 
                   trControl = bCtrl)
stopCluster(cl)

acp_logitdown$results %>%
  kable(digits=2) %>%
  kable_styling(latex_options = "HOLD_position")
parameter ROC Sens Spec Accuracy Kappa logLoss ROCSD SensSD SpecSD AccuracySD KappaSD logLossSD
none 0.49 0.52 0.43 0.52 -0.01 0.7 0.04 0.16 0.2 0.15 0.01 0.01

5.1.1.3 Over-sampling

bCtrl$sampling <- "up"
nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
acp_logitup <- train(bk ~ ., data = acp_train, method = "glm", 
                   trControl = bCtrl)
stopCluster(cl)

acp_logitup$results %>%
  kable(digits=2) %>%
  kable_styling(latex_options = "HOLD_position")
parameter ROC Sens Spec Accuracy Kappa logLoss ROCSD SensSD SpecSD AccuracySD KappaSD logLossSD
none 0.46 0.54 0.39 0.53 -0.01 0.69 0.03 0.14 0.17 0.13 0.01 0

5.2 MANUAL MODELS

set.seed(1)
inIndex <- createDataPartition(df$bk, p = .3, list = FALSE, times = 1)
train <- df[inIndex,]
test <- df[-inIndex,]
test$bk<-ifelse(test$bk==1,"Yes","No")
train$bk<-ifelse(train$bk==1,"Yes","No")

5.2.1 Logit models

5.2.1.1 Smote

library(themis)
bCtrl$sampling <- "smote"
nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
logitsmote <- train(bk ~ ., data = train, method = "glm",
trControl = bCtrl)
glm.fit: fitted probabilities numerically 0 or 1 occurred
stopCluster(cl)
logitsmote$results %>%
  kable(digits=2) %>%
kable_styling(latex_options = "HOLD_position")
parameter ROC Sens Spec Accuracy Kappa logLoss ROCSD SensSD SpecSD AccuracySD KappaSD logLossSD
none 0.83 0.87 0.66 0.87 0.2 0.53 0.04 0.03 0.11 0.02 0.06 0.26

5.2.1.2 Rose

bCtrl$sampling <- "rose"
nrcore <- 5
cl <- makeCluster(mc <- getOption("cl.cores", nrcore))
registerDoParallel(cl)
set.seed(777)
logitrose <- train(bk ~ ., data = train, method = "glm", trControl = bCtrl)
There were missing values in resampled performance measures.
Something is wrong; all the Accuracy metric values are missing:
      ROC           Sens          Spec        Accuracy       Kappa        logLoss   
 Min.   : NA   Min.   : NA   Min.   : NA   Min.   : NA   Min.   : NA   Min.   : NA  
 1st Qu.: NA   1st Qu.: NA   1st Qu.: NA   1st Qu.: NA   1st Qu.: NA   1st Qu.: NA  
 Median : NA   Median : NA   Median : NA   Median : NA   Median : NA   Median : NA  
 Mean   :NaN   Mean   :NaN   Mean   :NaN   Mean   :NaN   Mean   :NaN   Mean   :NaN  
 3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA  
 Max.   : NA   Max.   : NA   Max.   : NA   Max.   : NA   Max.   : NA   Max.   : NA  
 NA's   :1     NA's   :1     NA's   :1     NA's   :1     NA's   :1     NA's   :1    
Erreur : Stopping
Pred <- predict(logitsmote1, newdata =test)
confuslogsmote1<-caret::confusionMatrix(table(Pred, test$bk), positive="Yes", mode = "everything")
confuslogsmote1
Confusion Matrix and Statistics

     
Pred    No  Yes
  No  3983   36
  Yes  636  118
                                             
               Accuracy : 0.8592             
                 95% CI : (0.849, 0.869)     
    No Information Rate : 0.9677             
    P-Value [Acc > NIR] : 1                  
                                             
                  Kappa : 0.218              
                                             
 Mcnemar's Test P-Value : <0.0000000000000002
                                             
            Sensitivity : 0.76623            
            Specificity : 0.86231            
         Pos Pred Value : 0.15650            
         Neg Pred Value : 0.99104            
              Precision : 0.15650            
                 Recall : 0.76623            
                     F1 : 0.25991            
             Prevalence : 0.03226            
         Detection Rate : 0.02472            
   Detection Prevalence : 0.15797            
      Balanced Accuracy : 0.81427            
                                             
       'Positive' Class : Yes                
                                             

5.2.1.3 Down-sampling

5.2.1.4 Over-sampling

5.2.1.5 Smote

5.2.1.6 Rose

5.2.1.7 Up-sampling

5.2.1.8 Down-sampling

6 Comparaison des résultats

7 Conclusion et discussion

8 ANNEXES :

VOIR POUR FAIRE VRAI ANNEXES SUR R Script utilisé pour la génération des graphiques LHARBA

cat(readLines('Projet.rst'), sep = '\n')

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns

    df = pd.read_csv("/content/data (12).csv")

    p = df.iloc[: , 1:]
    p1 = p.iloc[:,0:24]
    p2 = p.iloc[:,24:48]
    p3 = p.iloc[:,48:72]
    p4 = p.iloc[:,72:]
    
    p.shape ,p1.shape, p2.shape, p3.shape, p4.shape

----------------------------------------------------------------

   
    plt.style.use('ggplot')
    ncols1 = 3
    nrows1 = int(np.ceil(len(p1.columns) / (1.0*ncols1)))
    fig, axes = plt.subplots(nrows=nrows1, ncols=ncols1, figsize=(150, 150))
    
    counter = 0
    for i in range(nrows1):
      for j in range(ncols1):
            ax = axes[i][j]
    
            if counter < len(p1.columns):
    
                ax.hist(p1[p1.columns[counter]], color='Blue', alpha=0.9, label='{}'.format(p1.columns[counter]))
                ax.set_xlabel(str(p1.columns[counter]), fontsize=60)
                ax.set_ylabel('Count', fontsize=10)
                ax.set_yscale('log')

            else:
                ax.set_axis_off()
    
            counter += 1
    fig1 = plt.gcf()
    plt.show()
    fig1.savefig("PP1.png")

    ncols2 = 4
    nrows2 = int(np.ceil(len(p2.columns) / (1.0*ncols2)))
    fig, axes = plt.subplots(nrows=nrows2, ncols=ncols2, figsize=(100, 100))
    
    counter = 0
    for i in range(nrows2):
      for j in range(ncols2):
            ax = axes[i][j]
    
            if counter < len(p2.columns):
                ax.hist(p2[p2.columns[counter]], color='blue', alpha=1, label='{}'.format(p2.columns[counter]))
                ax.set_xlabel(str(p2.columns[counter]), fontsize=50)
                ax.set_ylabel('Count', fontsize=10)
                ax.set_yscale('log')
    
            else:
                ax.set_axis_off()
    
            counter += 1
    
    
    fig2 = plt.gcf()
    plt.show()
    fig2.savefig("PP2.png")

    ncols3 = 4
    nrows3 = int(np.ceil(len(p3.columns) / (1.0*ncols3)))
    fig, axes = plt.subplots(nrows=nrows3, ncols=ncols3, figsize=(100, 100))
    
    counter = 0
    for i in range(nrows3):
      for j in range(ncols3):
            ax = axes[i][j]
    
            if counter < len(p3.columns):
                ax.hist(p3[p3.columns[counter]],color='blue', alpha=1, label='{}'.format(p3.columns[counter]))
                ax.set_xlabel(str(p3.columns[counter]), fontsize=50)
                ax.set_ylabel('Count', fontsize=10)
                ax.set_yscale('log')
                leg = ax.legend(loc='upper left')
                leg.draw_frame(False)
    
            else:
                ax.set_axis_off()
    
            counter += 1
    fig3 = plt.gcf()
    plt.show()
    fig3.savefig("P3.png")

    ncols4 = 4
    nrows4 = int(np.ceil(len(p4.columns) / (1.0*ncols4)))
    fig, axes = plt.subplots(nrows=nrows4, ncols=ncols4, figsize=(100, 100))
    
    counter = 0
    for i in range(nrows4):
      for j in range(ncols4):
            ax = axes[i][j]
    
            if counter < len(p4.columns):
    
                ax.hist(p4[p4.columns[counter]],color='blue', alpha=1, label='{}'.format(p4.columns[counter]))
                ax.set_xlabel(str(p4.columns[counter]), fontsize=50)
                ax.set_ylabel('Count', fontsize=10)
                ax.set_yscale('log')
                leg = ax.legend(loc='upper left')

            else:
                ax.set_axis_off()
    
            counter += 1
    
    fig4 = plt.gcf()
    plt.show()
    fig4.savefig("P4.png")
LS0tDQp0aXRsZTogIlByw6lkaXJlIGxhIGZhaWxsaXRlIGRlcyBlbnRyZXByaXNlcyA6IEV2aWRlbmNlcyBlbXBpcmlxdWVzIGTigJllbnRyZXByaXNlcyB0YcOvd2FuYWlzZXMiDQphdXRob3I6IA0KLSBDaGF0aWxsb24gTm91cmkNCi0gQ29sbWFpcmUgQ2hhcmxvdHRlDQotIE1lemRhciBNYXJ3YW4NCi0gVG91bG91c2UgU2Nob29sIG9mIEVjb25vbWljcw0KDQphYnN0cmFjdCA6ICJMaGFyYmEgSSBsb3ZlIGFic3RyYWN0Ig0KICANCg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgdG9jOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIA0KLS0tDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KG1vZGVsc3VtbWFyeSkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJldGljdWxhdGUpDQpgYGANCg0KYGBge3B5dGhvbiwgZWNobz1GQUxTRX0NCmltcG9ydCBwYW5kYXMgYXMgcGQNCmltcG9ydCBudW1weSBhcyBucA0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KaW1wb3J0IHNlYWJvcm4gYXMgc25zDQppbXBvcnQgc3RhdHNtb2RlbHMNCmZyb20gc3RhdHNtb2RlbHMuc3RhdHMub3V0bGllcnNfaW5mbHVlbmNlIGltcG9ydCB2YXJpYW5jZV9pbmZsYXRpb25fZmFjdG9yDQpgYGANCg0KDQojIEludHJvZHVjdGlvbg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeSI+IA0KDQpFbiAyMDIxIMOgIFRhaXdhbiwgbGUgbm9tYnJlIGTigJllbnRyZXByaXNlcyBkw6ljbGFyw6llcyBlbiBmYWlsbGl0ZSBlc3QgZW4gbW95ZW5uZSBkZSAyNDAwIHBhciBtb2lzLiBMYSBmYWlsbGl0ZSBkZXMgZW50cmVwcmlzZXMgcHLDqXNlbnRlIGRlcyBlbmpldXggZOKAmWVudmVyZ3VyZSBwYXJ0aWN1bGnDqHJlbWVudCBkdXJhbnQgbGEgY3Jpc2UgZGUgbGEgQ292aWQtMTksIG/DuSBkZSBub21icmV1c2VzIGVudHJlcHJpc2VzIMOgIHRyYXZlcnMgbGUgbW9uZGUgc2Ugc29udCByZXRyb3V2w6llcyBlbiBkaWZmaWN1bHTDqXMgZGFucyBs4oCZZXhlcmNpY2UgZGUgbGV1cnMgYWN0aXZpdMOpcy4gTm91cyBvYnNlcnZvbnMgYXVzc2kgdW5lIGhhdXNzZSBkZXMgcHLDqnRzIGdhcmFudGlzIHBhciBsZXMgw4l0YXRzIGRhbnMgY2VydGFpbnMgcGF5cywgYWZpbiBkZSBjb250ZW5pciBsZXMgZWZmZXRzIGRlIGxhIGNyaXNlIHN1ciBsZSBmaW5hbmNlbWVudCBkZXMgZW50cmVwcmlzZXMuIEFpbnNpIGlsIHNlcmFpdCBjcnVjaWFsIGRlIHRyb3V2ZXIgbGEgbcOpdGhvZG9sb2dpZSBhZMOpcXVhdGUgYWZpbiBkZSBwb3V2b2lyIHByw6lkaXJlIGxlcyBmYWlsbGl0ZXMgZOKAmWVudHJlcHJpc2VzIGRhbnMgbOKAmW9wdGlxdWUgZGUgcG91dm9pciBlc3RpbWVyIGxlcyBiZXNvaW5zIGRlIGNoYWN1bmUgZW4gbWF0acOocmUgZOKAmWFpZGVzIGV0IGRlIGZpbmFuY2VtZW50Lg0KDQpQbHVzaWV1cnMgdHJhdmF1eCBtb250cmVudCBxdWUgbGEgZmFpbGxpdGUgZOKAmXVuZSBlbnRyZXByaXNlIGVzdCBsZSBmcnVpdCBkZSBkaWZmaWN1bHTDqXMgZmluYW5jacOocmVzIG1lc3VyYWJsZXMgcGFyIHVuIGxhcmdlIHBhbmVsIGTigJlpbmRpY2F0ZXVycy4gQWluc2ksIG5vdHJlIMOpdHVkZSBjb25zaXN0ZXJhIMOgIGTDqXRlcm1pbmVyIHBsdXNpZXVycyBtb2TDqGxlcyBwcsOpZGljdGlmcyBzdXIgbGEgYmFzZSBk4oCZaW5kaWNhdGV1cnMgZmluYW5jaWVycyBkZSBs4oCZZW50cmVwcmlzZS4gTm91cyDDqXZhbHVlcm9ucyBwYXIgbGEgc3VpdGUgbGEgcHLDqWNpc2lvbiBwcsOpZGljdGl2ZSBkZSBjaGFjdW4gZGVzIG1vZMOobGVzIGV0IG5vdXMgY29tcGFyZXJvbnMgbGVzIHBlcmZvcm1hbmNlcyBkZXMgbWVpbGxldXJlcyBzcMOpY2lmaWNhdGlvbnMuIA0KDQoNCkxlcyBkb25uw6llcyBxdWUgbm91cyB1dGlsaXNlcm9ucyBwcm92aWVubmVudCBkdSAqKlRhaXdhbiBFY29ub21pYyBKb3VybmFsKiouIEVsbGVzIGNvdXZyZW50IGxhIHDDqXJpb2RlIDE5OTktMjAwOSBldCBjb25jZXJuZW50IGRlcyBlbnRyZXByaXNlcyB0YcOvd2FuYWlzZXMuIExhIGJhc2UgZGUgZG9ubsOpZXMgY29tcHRlIGFsb3JzIDY4MTkgb2JzZXJ2YXRpb25zIGFpbnNpIHF1ZSA5NSB2YXJpYWJsZXMsIGzigJl1bml0w6kgZOKAmW9ic2VydmF0aW9uIMOpdGFudCBsZXMgZW50cmVwcmlzZXMuDQoNCkzigJnDqXR1ZGUgZGUgbGEgcHLDqWRpY3Rpb24gZGVzIGZhaWxsaXRlcyBk4oCZZW50cmVwcmlzZXMgYSBkw6lqw6Agw6l0w6kgdHJhaXTDqSBwbHVzaWV1cnMgZm9pcy4gTGVzIGFydGljbGVzIHRyYWl0YW50IGRlIGNlIHN1amV0LCB1dGlsaXNlbnQgZGUgbXVsdGlwbGVzIG3DqXRob2RlcyBk4oCZYXBwcmVudGlzc2FnZSBhdXRvbWF0aXF1ZS4gTm90cmUgcHJvamV0IHNlIGJhc2VyYSBzdXIgbGEgY29tcGFyYWlzb24gZGUgcGx1c2lldXJzIG1vZMOobGVzIGRlICpjbGFzc2lmaWNhdGlvbiogZW4gdGVudGFudCBk4oCZeSBham91dGVyIGRlcyBhcHByb2NoZXMgcXVpIG7igJlvbnQgcGFzIMOpdMOpIHRyYWl0w6llcyBqdXNxdeKAmcOgIG1haW50ZW5hbnQuIE5vdXMgbm91cyBpbnNwaXJlcm9ucyDDqWdhbGVtZW50IGRlcyBtb2TDqGxlcyBkw6lqw6AgZWZmZWN0dcOpcyB0b3V0IGVuIGVzc2F5YW50IGRlIGxlcyBhcHByb2ZvbmRpci4gRGUgcGx1cywgbm91cyB0ZW50ZXJvbnMgZOKAmWFib3JkZXIgbGUgY2hvaXggZGVzIHZhcmlhYmxlcyBldCBsZXVyIHRyYWl0ZW1lbnQgZGUgbWFuacOocmUgZGlmZsOpcmVudGUuIA0KDQpOb3RyZSDDqXR1ZGUgcydhcnRpY3VsZXJhIGVuIGNpbnEgcGFydGllcyA6IA0KDQotICgyKSBQcmVtacOocmVtZW50LCBub3VzIHByw6lzZW50ZXJvbnMgdW5lIGJyw6h2ZSByZXZ1ZSBkZSBsaXR0w6lyYXR1cmUgcmVsYXRpdmUgw6Agbm90cmUgcHJvYmzDqW1hdGlxdWU7DQoNCi0gKDEpIExhIGRldXhpw6htZSBwYXJ0aWUgc2VyYSBjb25zYWNyw6llIGF1IG5ldHRveWFnZSBkZSBub3RyZSBiYXNlIGRlIGRvbm7DqWVzLCDDoCBsYSBwcsOpc2VudGF0aW9uIGRlcyB2YXJpYWJsZXMgcXVpIGxhIGNvbXBvc2VudCBldCDDoCB1bmUgYW5hbHlzZSBzdGF0aXN0aXF1ZSBkZXNjcmlwdGl2ZXMgZGUgbm9zIHByw6lkaWN0ZXVyczsgDQoNCi0gKDMpIEVuc3VpdGUsIGRhbnMgbGEgbWVzdXJlIG/DuSBub3VzIGZhaXNvbnMgZmFjZSDDoCB1bmUgZ3JhbmRlIGjDqXTDqXJvZ2VpbmVpdMOpIGRlcyBmcsOpcXVlbmNlcyBwb3VyIG5vdHJlIHZhcmlhYmxlIMOgIHByw6lkaXJlIGV0IGRvbmMgw6AgdW4gZMOpc8OpcXVpbGlicmUgZGVzIGNsYXNzZXMgKG91IENsYXNzIEltYmFsYW5jZSksIGRhbnMgY2V0dGUgcGFydGllLCBub3VzIHV0aWxpc2Vyb25zIGRlcyBtw6l0aG9kZXMgZCdhcHByZW50aXNzYWdlIHNlbnNpYmxlcyBhdXggY2/Du3RzIChvdSBjb3N0LXNlbnNpdGl2ZSBsZWFybmluZykgw6l0YW50IHVuZSBhcHByb2NoZSBjb3VyYW50ZSBwb3VyIHLDqXNvdWRyZSBjZSBwcm9ibMOobWU7DQoNCi0gKDQpIERhbnMgbGEgdHJvaXPDqG1lIHBhcnRpZSwgbm91cyB1dGlsaXNlcm9ucyBwbHVzaWV1cnMgbW9kw6hsZXMgcHLDqWRpY3RpZnMgZXQgbm91cyBqdXN0aWZpZXJvbnMgbGV1ciB1dGlsaXNhdGlvbjsNCg0KLSAoNSkgRW5maW4sIG5vdXMgY29tcGFyZXJvbnMgbGVzIHBlcmZvcm1hbmNlcyBkZSBub3MgbW9kw6hsZXMgcmVzcGVjdGlmcyBldCBub3VzIGZlcm9ucyB1biBjaG9peCBjb25jZXJuYW50IGxlcyBtZWlsbGV1cmVzIHNww6ljaWZpY2F0aW9ucy4gDQoNCg0KIyBSZXZ1ZSBkZSBsYSBsaXR0w6lyYXR1cmUgZXhpc3RhbnRlDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5Ij4gDQpMZXMgdHJhdmF1eCDDqXR1ZGlhbnQgbGEgcHLDqWRpY3Rpb24gZGUgbGEgZmFpbGxpdGUgZGVzIGVudHJlcHJpc2VzIHNvbnQgbm9tYnJldXggZXQgb250IGNvbW1lbmPDqSDDoCB2b2lyIGxlIGpvdXIgZMOocyBsZXMgYW5uw6llcyAxOTMwLiBMZXMgcHLDqWN1cnNldXJzIGRlIGNldHRlIHF1ZXN0aW9uIGNydWNpYWxlIG9udCBwdWJsacOpcyB1bmUgw6l0dWRlIHBhcnVlIGRhbnMgdW4gcmFwcG9ydCBkdSAqQnVyZWF1IG9mIEJ1c2luZXNzIFJlc2VhcmNoKigxOTMwKSwgcXVlc3Rpb25uYW50IHN1ciBsZXMgZMOpdGVybWluYW50cyBkZSBsYSBkw6lmYWlsbGFuY2UgZGVzIGVudHJlcHJpc2VzLiBM4oCZw6ljaGFudGlsbG9uIGRlIGzigJnDqXR1ZGUgY29tcG9ydGFpdCAyOSBlbnRyZXByaXNlcyBpbmR1c3RyaWVsbGVzIGV0IGNvbnNpc3RhaXQgw6AgY29tcGFyZXIgbGEgdmFsZXVyIGRlIDI0IHJhdGlvcyBmaW5hbmNpZXJzIMOgIGxhIG1veWVubmUgZGUgbOKAmcOpY2hhbnRpbGxvbiBldCBk4oCZZW4gdGlyZXIgZGVzIGNvbmNsdXNpb25zIHF1YW50IGF1eCBjYXJhY3TDqXJpc3RpcXVlcyBzaW1pbGFpcmVzIGRlcyBlbnRyZXByaXNlcyBkw6lmYWlsbGFudGVzLiBTYW5zIHZvdWxvaXIgb2ZmZW5zZXIgc2VzIHV0aWxpc2F0ZXVycywgY2V0dGUgbcOpdGhvZGUgZOKAmcOpdmFsdWF0aW9uIHVuaXZhcmnDqWUgZXN0IGJpZW4gw6l2aWRlbWVudCBjYWR1cXVlIGV0IGNvbXBvcnRlIHVuIG5vbWJyZSBpbXBvcnRhbnQgZGUgYmlhaXMuIA0KDQpE4oCZYXV0cmVzIMOpdHVkZXMgbXVsdGl2YXJpw6llcyBwdWJsacOpZXMgZGFucyBsZXMgYW5uw6llcyAxOTYwIMOgIDE5NzAgdXRpbGlzYWllbnQgcHJpbmNpcGFsZW1lbnQgbOKAmSoqQW5hbHlzZSBkaXNjcmltYW50ZSoqLiBEYW5zIGxlcyBhbm7DqWVzIDE5ODAgw6AgMTk5MCBs4oCZKipBbmFseXNlIExvZ2l0KiogZXQgbGVzICoqUsOpc2VhdXggTmV1cm9uYXV4Kiogw6l0YWllbnQgbGVzIG3DqXRob2RlcyBk4oCZw6l2YWx1YXRpb24gcHLDqWRvbWluYW50ZXMgKHZvaXIgQmVsbG92YXJ5ICgyMDA3KSBwb3VyIHVuIHLDqXN1bcOpIGhpc3RvcmlxdWUgZGUgbGEgcHLDqWRpY3Rpb24gZGUgbGEgZmFpbGxpdGUpLiANCg0KRGVzIMOpdHVkZXMgcGx1cyByw6ljZW50ZXMgdXRpbGlzYW50IG5vbiBzZXVsZW1lbnQgZOKAmWF1dHJlcyBtw6l0aG9kZXMgc3RhdGlzdGlxdWVzIG1haXMgw6lnYWxlbWVudCBkZXMgw6ljaGFudGlsbG9ucyBwbHVzIGxhcmdlIHNvbnQgcGx1cyBhZGFwdMOpZXMgw6Agbm90cmUgcHJvYmzDqW1hdGlxdWUuIFd1ICgyMDEwKSB1dGlsaXNlIGRlcyBkb25uw6llcyBkZSBzb2Npw6l0w6lzIGNvdMOpZXMgYXUgKk5ldyBZb3JrIFN0b2NrIEV4Y2hhbmdlKiBldCDDoCBsJypBbWVyaWNhbiBFeHByZXNzIENvbXBhbnkqIGNvdXZyYW50IGxhIHDDqXJpb2RlIDE5ODAgw6AgMjAwNi4gQ2lucSBtb2TDqGxlcyBzb250IHV0aWxpc8OpcyBldCBjb21wYXLDqXMgOiAqKkFuYWx5c2UgZGlzY3JpbWluYW50ZSBtdWx0aXBsZSoqLCAqKkxvZ2l0KiosICoqUHJvYml0KiosICoqSGF6YXJkIG1vZGVsKiosICoqQmxhY2stU2Nob2xlcyBtb2RlbCoqIGV0IGVuZmluIHVuICoqbW9kw6hsZSBsb2dpdCBtdWx0aS1ww6lyaW9kZSoqLiBMZXMgYXV0ZXVycyBlbiBhcnJpdmVudCDDoCBsYSBjb25jbHVzaW9uIHF1ZSBsZSAqKkhhemFyZCBtb2RlbCoqIGVtcHJ1bnTDqSDDoCBTaHVtd2F5ICgyMDAxKSBzdXJwYXNzZSBlbiB0ZXJtZSBkZSBwZXJmb3JtYW5jZSBwcsOpZGljdGl2ZSBsZXMgYXV0cmVzIG1vZMOobGVzLiBMZXMgdmFyaWFibGVzIGV4cGxpY2F0aXZlcyBmb3Vybmlzc2FudCBsZXMgcHLDqXZpc2lvbnMgbGVzIHBsdXMgZmlhYmxlcyBzdXIgbGVzIGZhaWxsaXRlcyBk4oCZZW50cmVwcmlzZXMgc29udCByZWxhdGl2ZXMgw6AgZGVzIGluZm9ybWF0aW9ucyBjb21wdGFibGVzLCBkZXMgZG9ubsOpZXMgZGUgbWFyY2jDqSBldCBkZXMgY2FyYWN0w6lyaXN0aXF1ZXMgZGUgbGEgc29jacOpdMOpLiANCg0KUGVydmFuIGV0IGFsLiAoMjAxMSksIHV0aWxpc2VudCBkZXMgZG9ubsOpZXMgZGUgMTU2IGVudHJlcHJpc2VzIGVuIENyb2F0aWUgcG91ciBsYSBww6lyaW9kZSBKYW52aWVyLUp1aW4gMjAxMCBldCBkZXMgcmF0aW8gZmluYW5jaWVycyBjb21tZSB2YXJpYWJsZXMgZXhwbGljYXRpdmVzLiBMZXMgZW50cmVwcmlzZXMgw6l0dWRpw6llcyBzb250IHBsdXTDtHQgaMOpdMOpcm9nw6huZXMuIEVuIGVmZmV0LCBsZXMgc2VjdGV1cnMgaW5kdXN0cmllbHMgc8OpbGVjdGlvbm7DqXMgY29tcHJlbm5lbnQgZGVzIGVudHJlcHJpc2VzIG9ww6lyYW50IGRhbnMgbGUgc2VjdGV1ciBtYW51ZmFjdHVyaWVyIGV0IGxlIGNvbW1lcmNlIGRlIGdyb3MuIExlcyBlbnRyZXByaXNlcyBzYWluZXMgZXQgZW4gZmFpbGxpdGUgc29udCBkdSBtw6ptZSBub21icmUgZXQgc29udCBzw6lsZWN0aW9ubsOpZXMgZGUgbWFuacOocmUgYWzDqWF0b2lyZS4gIExlcyBhdXRldXJzIHV0aWxpc2VudCBkZXV4IG1vZMOobGVzIDogKipSw6lncmVzc2lvbiBsb2dpc3RpcXVlKiogZXQgKipBbmFseXNlIGRpc2NyaW1pbmFudGUqKi4gTGUgbW9kw6hsZSBk4oCZQW5hbHlzZSBkaXNjcmltaW5hbnRlIGEgbGEgcHLDqWNpc2lvbiBsYSBwbHVzIG1vZGVzdGUgZGFucyBsYSBwcsOpZGljdGlvbiBkZXMgZW50cmVwcmlzZXMgZW4gZmFpbGxpdGUsIGVuIGVmZmV0LCBlbGxlIGVzdCBkZSA3OSw1ICUgY29udHJlIDg1LjkgJSBwb3VyIGxlIG1vZMOobGUgZGUgUsOpZ3Jlc3Npb24gbG9naXN0aXF1ZS4gDQoNCk11LVllbiBDaGVuICgyMDExKSwgdXRpbGlzZSB1bmUgYmFzZSBkZSBkb25uw6llcyBjb21wb3J0YW50IDIwMCBzb2Npw6l0w6lzIGNvdMOpZXMgw6AgbGEgKlRhaXdhbiBTdG9jayBFeGNoYW5nZSBDb3Jwb3JhdGlvbiouIEzigJlhdXRldXIgdXRpbGlzZSBldCBjb21wYXJlIDkgbW9kw6hsZXMgZGlmZsOpcmVudHMgIGF2ZWMgZGVzIG3DqXRob2RlcyByZWxhdGl2ZXMgw6AgbGEgY2xhc3NpZmljYXRpb24gcGFyIGFyYnJlIGRlIGTDqWNpc2lvbiwgYXV4IHLDqXNlYXV4IG5ldXJvbmF1eCBldCBhdXggdGVjaG5pcXVlcyBkZSBjYWxjdWwgw6l2b2x1dGlmLiBTb24gbW9kw6hsZSBsZSBwbHVzIHBlcmZvcm1hbnQgZW4gdGVybWUgZGUgcHLDqWRpY3Rpb24gZXN0IGxlICoqUFNPLVNWTSoqICgqUGFydGljbGUgU3dhcm0gT3B0aW1pemF0aW9uLVN1cHBvcnQgVmVjdG9yIE1hY2hpbmUqKS4gTOKAmXV0aWxpc2F0aW9uIGTigJl1bmUgKipBbmFseXNlIGVuIGNvbXBvc2FudGUgcHJpbmNpcGFsZSoqIGEgcGVybWlzIGRlIGTDqXRlcm1pbmVyIGxlcyB2YXJpYWJsZXMgYXBwcm9wcmnDqWVzIMOgIGzigJnDqXR1ZGUgcGFybWkgNDIgcmF0aW9zLCBkb250IDMzIGZpbmFuY2llcnMsIDggbm9uIGZpbmFuY2llcnMgZXQgMSBpbmRpY2UgbWFjcm/DqWNvbm9taXF1ZS4gU2V1bHMgOCBkZXMgNDIgcmF0aW9zIG9udCDDqXTDqSBnYXJkw6llcyBhcHLDqHMgbOKAmWFuYWx5c2UgZW4gY29tcG9zYW50ZSBwcmluY2lwYWxlIGV0IHRvdXRlcyDDqXRhaWVudCBkZXMgcmF0aW9zIGZpbmFuY2llcnMuIEzigJlhdXRldXIgZW4gY29uY2x1IGRvbmMgcXVlIGxlcyByYXRpb3MgZmluYW5jaWVycyBvbnQgdW4gZWZmZXQgcGx1cyBpbXBvcnRhbnQgc3VyIGxhIHBlcmZvcm1hbmNlIGRlIGxhIHByw6lkaWN0aW9uIGZpbmFuY2nDqHJlIHF1ZSBsZXMgcmF0aW9zIG5vbiBmaW5hbmNpZXJzIGV0IGxlcyBpbmRpY2VzIG1hY3Jvw6ljb25vbWlxdWVzLg0KDQpGaW5hbGVtZW50LCBEZXJvbiBMaWFuZyBldCBhbC4gKDIwMTYpIHV0aWxpc2VudCBsYSBtw6ptZSBiYXNlIGRlIGRvbm7DqWVzIHF1ZSBjZWxsZSBkZSBub3RyZSDDqXR1ZGUuIFBvdXIgc8OpbGVjdGlvbm5lciBsZXMgdmFyaWFibGVzIGlscyB1dGlsaXNlbnQgY2lucSBtw6l0aG9kZXMgOiAqKkFuYWx5c2UgZGlzY3JpbWluYW50ZSBwYXIgw6l0YXBlcyoqLCBsYSAqKnLDqWdyZXNzaW9uIGxvZ2lzdGlxdWUgcGFyIMOpdGFwZXMqKiwgbGUgKip0ZXN0IHQqKiwgbCcqKmFsZ29yaXRobWUgZ8OpbsOpdGlxdWUqKiBldCBsJyoqw6lsaW1pbmF0aW9uIHLDqWN1cnNpdmUqKi4gSWxzIGVuIGNvbmNsdWVudCBxdWUgbGEgY29tYmluYWlzb24gZGUgcmF0aW9zIGZpbmFuY2llcnMgZXQgZOKAmWluZGljYXRldXJzIGRlIGdvdXZlcm5hbmNlIGQnZW50cmVwcmlzZSBzb250IHBsdXMgYWRhcHTDqXMgcXVlIGzigJl1dGlsaXNhdGlvbiBleGNsdXNpdmUgZGUgcmF0aW9zIGZpbmFuY2llcnMgcG91ciBwcsOpZGlyZSBsYSBmYWlsbGl0ZSBkZXMgZW50cmVwcmlzZXMuIExldXIgbW9kw6hsZXMgbGVzIHBsdXMgcGVyZm9ybWFudHMgc29udCA6ICoqc3RlcHdpc2UgZGlzY3JpbWluYW50IGFuYWx5c2lzKiogKFNEQSkgZXQgKipzdXBwb3J0IHZlY3RvciBtYWNoaW5lKiouIA0KCQ0KTGVzIMOpdHVkZXMgc2UgcGVuY2hhbnQgc3VyIGNldHRlIHByb2Jsw6ltYXRpcXVlIHV0aWxpc2VudCBkZXMgZG9ubsOpZXMgZGUgbmF0dXJlIGRpZmbDqXJlbnRlcyAodHlwZSBk4oCZZW50cmVwcmlzZXMsIHZhcmlhYmxlcyBleHBsaWNhdGl2ZXMsIHDDqXJpb2RlIGV0Yy4pICwgZXQgbGEgZGl2ZXJnZW5jZSBkZSBsZXVycyBjb25jbHVzaW9ucyByZWxhdGl2ZXMgYXV4IG1vZMOobGVzIGxlcyBwbHVzIHBlcmZvcm1hbnQgZGFucyBsYSBwcsOpZGljdGlvbiBkZSBsYSBmYWlsbGl0ZSBk4oCZZW50cmVwcmlzZXMgc3VnZ8OocmUgcXVlIGNlcnRhaW5lcyBtb2TDqWxpc2F0aW9ucyBzZW1ibGVudCDDqnRyZSBwbHVzIGFkYXB0w6llcyBlbiBmb25jdGlvbiBkZXMgZG9ubsOpZXMgw6AgZGlzcG9zaXRpb24uIA0KDQo8L2Rpdj4NCg0KDQojIERvbm7DqWVzDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZGYgPC0gcmVhZF9jc3YoIkM6L1VzZXJzLzMzNjY2L0Rlc2t0b3AvTTIvUHJvamV0X3N0YXQvZGF0YS5jc3YiKQ0KYGBgDQoNCkJMQUJMQUJMQQ0KDQoNCiMjIFbDqXJpZmljYXRpb25zIGRlcyBkb25uw6llcw0KDQpgYGB7cn0NCiMgTm9tYnJlIHRvdGFsIGRlIHZhbGV1cnMgbWFucXVhbnRlcw0Kc3VtKGlzLm5hKGRmKSkNCmBgYA0KDQpgYGB7cn0NCiNOb21icmUgdG90YWwgZGUgZHVwbGljYXRzDQpzdW0oZHVwbGljYXRlZChkZikpDQpgYGANCg0KDQpgYGB7cn0NCmRpbShkZikNCmBgYA0KDQojIyBWYXJpYWJsZSBkJ2ludGVyw6p0DQoNCmBgYHtyfQ0KbmFtZXMoZGYpW25hbWVzKGRmKSA9PSAiQmFua3J1cHQ/Il0gPC0gJ2JrJw0KZGYkYmsgPC0gYXMuZmFjdG9yKGRmJGJrKQ0KZGYkYmsgPC0gcmVsZXZlbChkZiRiaywgcmVmID0gMSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFzdW1tYXJ5X3NraW0oZGYsIHR5cGUgPSAiY2F0ZWdvcmljYWwiLCBvdXRwdXQgPSAia2FibGVFeHRyYSIpDQpgYGANCg0KYGBge3J9DQpwY3RfZm9ybWF0ID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IC4xKQ0KcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gYmssIGZpbGwgPSBiaykpICsNCiAgZ2VvbV9iYXIoKSArDQogIGdlb21fdGV4dCgNCiAgICBhZXMoDQogICAgICBsYWJlbCA9IHNwcmludGYoDQogICAgICAgICclZCAoJXMpJywNCiAgICAgICAgLi5jb3VudC4uLA0KICAgICAgICBwY3RfZm9ybWF0KC4uY291bnQuLiAvIHN1bSguLmNvdW50Li4pKQ0KICAgICAgKQ0KICAgICksDQogICAgc3RhdCA9ICdjb3VudCcsDQogICAgbnVkZ2VfeSA9IC4yLA0KICAgIGNvbG91ciA9ICdEYXJrIGJsdWUnLA0KICAgIHNpemUgPSA1KQ0KIA0KcA0KYGBgDQoNCg0KIyMgUHJlZGljdGV1cnMNCg0KTGVzIHZhcmlhYmxlcyBleG9nw6huZXMgb250IGQnYWJvcmQgw6l0w6kgbm9ybWFsaXPDqWVzIHBhciBsYSBtw6l0aG9kZSBkaXRlcyBkdSAiZmVhdHVyZSBzY2FsaW5nIiA6IA0KJCQgRih4X2kpID0gXGZyYWN7eF9pIFxzcGFjZS0gXHNwYWNlIG1pbih4KX17IG1heCh4KSBcc3BhY2UgLSBcc3BhY2UgbWluKHgpfSQkDQoNCkRlIGNlIGZhaXQgbGVzICMjI1BLIENBIEEgRVRFIE5PUk1BTElaRSA/ICMjIyMNCg0KIyMjIFN0YXRpc3RpcXVlcyBkZXNjcml0cHRpdmVzDQoNCmBgYHtyfQ0KdGFibGUxIDwtIHBzeWNoOjpkZXNjcmliZShkZiwgc2tldyA9IEYsIHJhbmdlcz1GKQ0KDQp0YWJsZTEgJT4lDQogIGtibChjYXB0aW9uID0gIlJlY3JlYXRpbmcgYm9va3RhYnMgc3R5bGUgdGFibGUiKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIkNhbWJyaWEiKQ0KYGBgDQoNCiMjIyBEaXN0cmlidXRpb24gZGVzIHByw6lkaWN0ZXVycw0KDQpgYGB7ciwgZWNobz1GYWxzZSwgZmlnLmNhcD0iMyIsIG91dC53aWR0aCA9ICcxMDAlJ30NCmluY2x1ZGVfZ3JhcGhpY3MoIlAzLnBuZyIpDQppbmNsdWRlX2dyYXBoaWNzKCJQNC5wbmciKQ0KaW5jbHVkZV9ncmFwaGljcygiUFAyLnBuZyIpDQppbmNsdWRlX2dyYXBoaWNzKCJQUDEucG5nIikNCmBgYA0KDQpMb3JzcXVlIG5vdXMgb2JzZXJ2b25zIGxlcyB2YXJpYWJsZXMgZGUgbGEgZGF0YXNldA0KLW9uIHZvaXQgcXVlIGNlcnRhaW5lcyBzb250IGRlcyB2YXJpYW50ZXMgZGVzIGF1dHJlcyB0ZWwgcXVlIHVuIHJhdGlvIGF2YW50IC8gYXByZXMgaW50ZXJldCwgb24gZW4gZ2FyZGUgdW4gw6AgY2hhcXVlIGZvaXMNCi1JbCB5J2EgZGVzIHZhcmlhYmxlcyBxdWkgc2UgcmVww6h0ZW50IGV0IG9uIGxlcyBtw6ptZSB2YWxldXJzIGRpc3RyaWJ1dGlvbiAoZWc6IEN1cnJlbnQgTGlhYmlsaXR5IHRvIExpYWJpbGl0eSBldCBMaWFiaWxpdHkgdG8gTGlhYmlsaXR5KQ0KLUNlcnRhaW5zIHJhdGlvcyBzb250IG4nb250IHF1ZSBkZSBjaGFuZ2VtZW50IGxldXJzIGTDqW5vbWluYXRldXJzDQoNCg0KIyAqRmVhdHVyZXMgc2VsZWN0aW9uKg0KDQpCTEFCTEENCg0KDQpgYGB7cn0NCmluY2x1ZGVfZ3JhcGhpY3MoIkdSQVBIMS5kcmF3aW8ucG5nIikNCmBgYA0KDQoNCg0KDQojIyBTZWxlY3Rpb24gcHLDqWxpbWluYWlyZQ0KDQoNCiMjI1ZhcmlhYmxlIGludXRpbGVzIHJlZG9uZGFudGVzDQogDQpgYGB7cn0NCmNvbG5hbWVzKGRmKQ0KZGZbICxjKDQsMyw4LDE4LDE5LDIzLDc5LDY3LDc4KV0gPC0gbGlzdChOVUxMKQ0KDQpgYGANCiANCg0KIyMjIFplcm8tVmFyaWFuY2UgcHJlZGljdG9yKg0KDQpgYGB7cn0NCnByZWRpY3RvcnMgPC0gZGZbLC1jKDEpXQ0Kcm1wMTwtbmFtZXMocHJlZGljdG9ycylbbmVhclplcm9WYXIocHJlZGljdG9ycyldICMgTm91cyBkb25uZSBsZXMgdmFyaWFibGVzIG5lIHByZW5hbnQgcXUndW5lIHNldWwgdmFsZXVyIG91IGF5YW50IHVuZSB2YXJpYW5jZSBxdWFzaS1udWxsZQ0KcHJpbnQocm1wMSkNCnRhYmxlKHByZWRpY3RvcnMkYE5ldCBJbmNvbWUgRmxhZ2ApDQp0YWJsZShwcmVkaWN0b3JzJGBMaWFiaWxpdHktQXNzZXRzIEZsYWdgKQ0KYGBgDQoNCmBgYHtyfQ0KZGZbICxjKCJMaWFiaWxpdHktQXNzZXRzIEZsYWciLCAiTmV0IEluY29tZSBGbGFnIildIDwtIGxpc3QoTlVMTCkNCmBgYA0KDQoNCk5vdXMgcG91dm9ucyBkJ29yZXMgZXQgZMOpamEgcmV0aXJlciBsZXMgdmFyaWFibGVzICpMaWFiaWxpdHktQXNzZXRzIEZsYWcqIGV0ICpOZXQgSW5jb21lIEZsYWcqLiBFbiBlZmZldCwgbGEgdmFyaWFibGUgKkxpYWJpbGl0eS1Bc3NldHMgRmxhZyogcG9zc8OoZGUgdW5lIHZhcmlhbmNlIHRyw6hzIHByb2NoZXMgZGUgMCwgY2UgcXVpIHZldXQgZGlyZSBxdSdlbGxlIG5lIHByZW5kIHBhcyBiZWFjb3VwIGRlIHZhbGV1cnMgZGlmZsOpcmVudGVzLiBFbnN1aXRlLCBjb25jZXJuYW50ICAgKk5ldCBJbmNvbWUgRmxhZyosIGxhIHZhcmlhYmxlIG5lIGNvbXBvcnRlIHF1J3VuZSBzZXVsZSB2YWxldXIgdW5pcXVlIMOpZ2FsZSDDoCAxLg0KDQojIyMgVmFyaWFuY2UgaW5mbGF0aW9uIEZhY3RvciBhbmQgQ29ycmVsYXRpb24gcmF0aW9zDQogDQpgYGB7cHl0aG9ufQ0KZGYgPSBwZC5yZWFkX2NzdigiQzovVXNlcnMvMzM2NjYvRGVza3RvcC9NMi9Qcm9qZXRfc3RhdC9kYXRhLmNzdiIpDQoNCnAgPSBkZg0KcC5kcm9wKHAuY29sdW1uc1tbMCwzLDIsNywxNywxOCwyMiw3OCw2NiwgOTQsIDg1LCA3N11dLCBheGlzID0gMSwgaW5wbGFjZT1UcnVlKQ0KYGBgDQoNCg0KDQpKYW1lcyBHLCBXaXR0ZW4gRCwgSGFzdGllIFQsIFRpYnNoaXJhbmkgUi4gQW4gSW50cm9kdWN0aW9uIHRvIFN0YXRpc3RpY2FsIExlYXJuaW5nOiBXaXRoIEFwcGxpY2F0aW9ucyBpbiBSLiAxc3QgZWQuIDIwMTMsIENvcnIuIDd0aCBwcmludGluZyAyMDE3IGVkaXRpb24uIFNwcmluZ2VyOyAyMDEzLiAtLT4gVklGIDEwIGlzIHByb2JsZW1hdGljDQoNCmBgYHtweXRob24sIHdhcm5pbmc9RkFMU0V9DQp2aWZfZGF0YSA9IHBkLkRhdGFGcmFtZSgpDQp2aWZfZGF0YVsiZmVhdHVyZSJdID0gcC5jb2x1bW5zDQp2aWZfZGF0YVsiVklGIl0gPSBbdmFyaWFuY2VfaW5mbGF0aW9uX2ZhY3RvcihwLnZhbHVlcywgaSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGkgaW4gcmFuZ2UobGVuKHAuY29sdW1ucykpXQ0KDQoNCg0KdjEgPSBwZC5EYXRhRnJhbWUodmlmX2RhdGFbKHZpZl9kYXRhWydWSUYnXT49MTApXSkNCg0KdjEgPSB2MS5zb3J0X3ZhbHVlcyhieT1bJ1ZJRiddLCBpbnBsYWNlPUZhbHNlKQ0KcHJpbnQodjEpDQp2aWZsaXN0ID0gdjFbJ2ZlYXR1cmUnXS50b2xpc3QoKQ0KYGBgDQoNCmBgYHtyfQ0KZGZbICxjKCdOZXQgSW5jb21lIHRvIFRvdGFsIEFzc2V0cycsJ0VxdWl0eSB0byBMb25nLXRlcm0gTGlhYmlsaXR5JywnUGVyIFNoYXJlIE5ldCBwcm9maXQgYmVmb3JlIHRheCAoWXVhbiknLCAnUGVyc2lzdGVudCBFUFMgaW4gdGhlIExhc3QgRm91ciBTZWFzb25zJywgJ05ldCBwcm9maXQgYmVmb3JlIHRheC9QYWlkLWluIGNhcGl0YWwnLCAnQ2FzaCBGbG93IHRvIFNhbGVzJywgJ0ludmVudG9yeSBhbmQgYWNjb3VudHMgcmVjZWl2YWJsZS9OZXQgdmFsdWUnLCAnQm9ycm93aW5nIGRlcGVuZGVuY3knLCAnV29ya2luZyBDYXBpdGFsL0VxdWl0eScsICdXb3JraW5nIGNhcGl0Y2FsIFR1cm5vdmVyIFJhdGUnLCAnUmVndWxhciBOZXQgUHJvZml0IEdyb3d0aCBSYXRlJywgJyBmdGVyLXRheCBOZXQgUHJvZml0IEdyb3d0aCBSYXRlJywgJ0xpYWJpbGl0eSB0byBFcXVpdHknLCAnTm9uLWluZHVzdHJ5IGluY29tZSBhbmQgZXhwZW5kaXR1cmUvcmV2ZW51ZScsICdDb250aW51b3VzIGludGVyZXN0IHJhdGUgKGFmdGVyIHRheCknLCAnUmVhbGl6ZWQgU2FsZXMgR3Jvc3MgTWFyZ2luJywgJ09wZXJhdGluZyBQcm9maXQgUmF0ZScsICdBZnRlci10YXggbmV0IEludGVyZXN0IFJhdGUnLCAnR3Jvc3MgUHJvZml0IHRvIFNhbGVzJywgJ09wZXJhdGluZyBHcm9zcyBNYXJnaW4nLCAnTmV0IHdvcnRoL0Fzc2V0cycsICdEZWJ0IHJhdGlvICUnLCAnQ3VycmVudCBBc3NldHMvVG90YWwgQXNzZXRzJywgJ0N1cnJlbnQgTGlhYmlsaXR5IHRvIEFzc2V0cycsICcgb3JraW5nIENhcGl0YWwgdG8gVG90YWwgQXNzZXRzJyldIDwtIGxpc3QoTlVMTCkNCmBgYA0KDQoNCiMjIyBQZXJ0aW5lbmNlIGRlcyB2YXJpYWJsZXMNCg0KYGBge3J9DQpsaWJyYXJ5KERpc2NyaU1pbmVyKSAjIExhIGZvbmN0aW9uIGMnZXN0IFF1YW50aS1RdWFsaQ0KDQpwcmVkIDwtIGNvbG5hbWVzKGRmWywtMV0pDQoNCnByZWQgPC0gYXMuZGF0YS5mcmFtZShwcmVkKQ0KcHJlZCRjb3JfcmF0aW8gPC0gTkENCg0KcHJlZD1hcy5tYXRyaXgocHJlZCkNCg0KZm9yIChpIGluIDE6NjEpIHsNCiAgDQogICAgZ3JwPWFzLmZhY3RvcihkZiRiaykNCiAgICBuYW1lID0gYXMuY2hhcmFjdGVyKHByZWRbaSwxXSkNCiAgICBwcmVkW2ksMl0gPSBhcy5udW1lcmljKGNvclJhdGlvKGRmW1tuYW1lXV0sZ3JwKSkNCiAgICANCn0NCg0KcHJlZD1hcy5kYXRhLmZyYW1lKHByZWQpDQpwcmVkW29yZGVyKHByZWQkY29yX3JhdGlvLCBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCiAgICAgDQpgYGANCg0KDQpgYGB7cn0NCmxoYXJiYSA8LSBwcmVkW3ByZWQkY29yX3JhdGlvIDw9IG1lZGlhbihwcmVkJGNvcl9yYXRpbyksIF0NCmxoYXJiYSA8LSBhcy5jaGFyYWN0ZXIobGhhcmJhJHByZWQpDQpwcmludChsaGFyYmEpDQpgYGANCg0KYGBge3J9DQpmb3IgKGNvbCBpbiBsaGFyYmEpDQogICAgZGZbW2NvbF1dPC1OVUxMDQpgYGANCg0KDQoNCmBgYHtyfQ0KZGltKGRmKQ0KDQpgYGANCg0KIyMgU0VMRUNUSU9OIDENCg0KIyMgQVBQUk9DSEUgUEFSIENPTVBPU0FOVEVTIFBSSU5DSVBBTEVTDQoNCmBgYHtyfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpIyBJbiBvcmRlciB0byBkaXNhYmxlIFNjaWVudGlmaWMgTm90YXRpb24NCg0KbXlQcjwtcHJjb21wKGRmWywtMV0sc2NhbGU9RkFMU0UpICMgQ3JlYXRpbmcgUENzDQpzdW1tYXJ5KG15UHIpDQoNCmBgYA0KDQpgYGB7cn0NCnBsb3QobXlQcikNCg0KYGBgDQoNCmBgYHtyfQ0KTG9hZGluZ3MgPC0gbXlQciRyb3RhdGlvbiAjIEV4dHJhY3RpbmcgUENzIGZvciByZWdyZXNzaW9uIA0KDQpheGVzIDwtIHByZWRpY3QobXlQciwgbmV3ZGF0YSA9IGRmKQ0KYWNwX2RmIDwtIGNiaW5kKGRmWzFdLCBheGVzKSAjIGFqb3V0IGRlcyBQY3MgZGFucyB1bmUgbm91dmVsbGUgYmFzZSBkZSBkb25uw6llcyANCmFjcF9kZlssNDozMV08LWxpc3QoTlVMTCkNCmBgYA0KDQoNCg0KDQoNCg0KDQogDQojIE1vZMOpbGlzYXRpb24NCg0KDQoNCg0KYGBge3J9DQppbmNsdWRlX2dyYXBoaWNzKCJHUkFQSDIuZHJhd2lvLnBuZyIpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocGFyYWxsZWwpDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQojIGNvbnRyb2wgdmFyaWFibGVzDQptZXRob2QgPC0gImJvb3QiDQpudW1iZXJzIDwtIDMwICMgTnVtYmVyIG9mIGJvb3RzdHJhcCBzYW1wbGVzDQpiVHVuZXMgPC0gMzAgIyB0dW5lIG51bWJlciBvZiBtb2RlbHMNCnNlZWQgPC0gNzc3DQoNCiMgU2VlZHMNCmJTZWVkcyA8LSBib290c2V0U2VlZHMobWV0aG9kID0gbWV0aG9kLCBudW1iZXJzID0gbnVtYmVycywgdHVuZXMgPSBiVHVuZXMsDQpzZWVkID0gc2VlZCkNCiMgQ29uZmlndXJlIHRoZSB0cmFpbkNvbnRyb2wgYXJndW1lbnQgZm9yIGNyb3NzLXZhbGlkYXRpb24NCnNpeFN0YXRzIDwtIGZ1bmN0aW9uKC4uLikgYyh0d29DbGFzc1N1bW1hcnkoLi4uKSwNCmRlZmF1bHRTdW1tYXJ5KC4uLiksIG1uTG9nTG9zcyguLi4pKQ0KYkN0cmwgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9IG1ldGhvZCwgbnVtYmVyID0gbnVtYmVycywNCmNsYXNzUHJvYnMgPSBUUlVFLCBzYXZlUHJlZGljdGlvbnMgPSBUUlVFLA0Kc2VlZHMgPSBiU2VlZHMsIHN1bW1hcnlGdW5jdGlvbiA9IHNpeFN0YXRzLA0KYWxsb3dQYXJhbGxlbCA9IFRSVUUpDQoNCmBgYA0KDQojIyBQQyBNb2RlbHMNCg0KDQpgYGB7cn0NCnNldC5zZWVkKDEpDQppbkluZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oYWNwX2RmJGJrLCBwID0gLjMsIGxpc3QgPSBGQUxTRSwgdGltZXMgPSAxKQ0KYWNwX3RyYWluIDwtIGFjcF9kZltpbkluZGV4LF0NCmFjcF90ZXN0IDwtIGFjcF9kZlstaW5JbmRleCxdDQoNCmFjcF90ZXN0JGJrPC1pZmVsc2UoYWNwX3Rlc3QkYms9PTEsIlllcyIsIk5vIikNCg0KYWNwX3RyYWluJGJrPC1pZmVsc2UoYWNwX3RyYWluJGJrPT0xLCJZZXMiLCJObyIpDQpgYGANCg0KDQoNCg0KIyMjIExvZ2l0IG1vZGVscw0KDQoNCiRTTU9URSQNCg0KYGBge3J9DQpsaWJyYXJ5KHRoZW1pcykNCmJDdHJsJHNhbXBsaW5nIDwtICJzbW90ZSINCm5yY29yZSA8LSA1DQpjbCA8LSBtYWtlQ2x1c3RlcihtYyA8LSBnZXRPcHRpb24oImNsLmNvcmVzIiwgbnJjb3JlKSkNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkNCnNldC5zZWVkKDc3NykNCmFjcF9sb2dpdHNtb3RlIDwtIHRyYWluKGJrIH4gLiwgZGF0YSA9IGFjcF90cmFpbiwgbWV0aG9kID0gImdsbSIsDQp0ckNvbnRyb2wgPSBiQ3RybCkNCnN0b3BDbHVzdGVyKGNsKQ0KYWNwX2xvZ2l0c21vdGUkcmVzdWx0cyAlPiUNCiAga2FibGUoZGlnaXRzPTIpICU+JQ0Ka2FibGVfc3R5bGluZyhsYXRleF9vcHRpb25zID0gIkhPTERfcG9zaXRpb24iKQ0KYGBgDQoNCg0KIyMjIyBSb3NlIA0KDQoNCmBgYHtyfQ0KYkN0cmwkc2FtcGxpbmcgPC0gInJvc2UiDQoNCm5yY29yZSA8LSA1DQpjbCA8LSBtYWtlQ2x1c3RlcihtYyA8LSBnZXRPcHRpb24oImNsLmNvcmVzIiwgbnJjb3JlKSkNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkNCnNldC5zZWVkKDc3NykNCmFjcF9sb2dpdHJvc2UgPC0gdHJhaW4oYmsgfiAuLCBkYXRhID0gYWNwX3RyYWluLCBtZXRob2QgPSAiZ2xtIiwgdHJDb250cm9sID0gYkN0cmwpDQpzdG9wQ2x1c3RlcihjbCkNCmFjcF9sb2dpdHJvc2UkcmVzdWx0cyAlPiUNCiAga2FibGUoZGlnaXRzPTIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGxhdGV4X29wdGlvbnMgPSAic3RyaXBlZCIpDQpgYGANCg0KDQojIyMjIERvd24tc2FtcGxpbmcNCg0KDQpgYGB7cn0NCmJDdHJsJHNhbXBsaW5nIDwtICJkb3duIg0KbnJjb3JlIDwtIDUNCmNsIDwtIG1ha2VDbHVzdGVyKG1jIDwtIGdldE9wdGlvbigiY2wuY29yZXMiLCBucmNvcmUpKQ0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0Kc2V0LnNlZWQoNzc3KQ0KYWNwX2xvZ2l0ZG93biA8LSB0cmFpbihiayB+IC4sIGRhdGEgPSBhY3BfdHJhaW4sIG1ldGhvZCA9ICJnbG0iLCANCiAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBiQ3RybCkNCnN0b3BDbHVzdGVyKGNsKQ0KDQphY3BfbG9naXRkb3duJHJlc3VsdHMgJT4lDQogIGthYmxlKGRpZ2l0cz0yKSAlPiUNCiAga2FibGVfc3R5bGluZyhsYXRleF9vcHRpb25zID0gIkhPTERfcG9zaXRpb24iKQ0KYGBgDQoNCiMjIyMgT3Zlci1zYW1wbGluZw0KYGBge3J9DQpiQ3RybCRzYW1wbGluZyA8LSAidXAiDQpucmNvcmUgPC0gNQ0KY2wgPC0gbWFrZUNsdXN0ZXIobWMgPC0gZ2V0T3B0aW9uKCJjbC5jb3JlcyIsIG5yY29yZSkpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQpzZXQuc2VlZCg3NzcpDQphY3BfbG9naXR1cCA8LSB0cmFpbihiayB+IC4sIGRhdGEgPSBhY3BfdHJhaW4sIG1ldGhvZCA9ICJnbG0iLCANCiAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBiQ3RybCkNCnN0b3BDbHVzdGVyKGNsKQ0KDQphY3BfbG9naXR1cCRyZXN1bHRzICU+JQ0KICBrYWJsZShkaWdpdHM9MikgJT4lDQogIGthYmxlX3N0eWxpbmcobGF0ZXhfb3B0aW9ucyA9ICJIT0xEX3Bvc2l0aW9uIikNCmBgYA0KDQojIyBNQU5VQUwgTU9ERUxTDQoNCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRmJGJrLCBwID0gLjMsIGxpc3QgPSBGQUxTRSwgdGltZXMgPSAxKQ0KdHJhaW4gPC0gZGZbaW5JbmRleCxdDQp0ZXN0IDwtIGRmWy1pbkluZGV4LF0NCnRlc3QkYms8LWlmZWxzZSh0ZXN0JGJrPT0xLCJZZXMiLCJObyIpDQp0cmFpbiRiazwtaWZlbHNlKHRyYWluJGJrPT0xLCJZZXMiLCJObyIpDQpgYGANCg0KDQoNCiMjIyBMb2dpdCBtb2RlbHMNCg0KIyMjIyBTbW90ZQ0KYGBge3J9DQpsaWJyYXJ5KHRoZW1pcykNCmJDdHJsJHNhbXBsaW5nIDwtICJzbW90ZSINCm5yY29yZSA8LSA1DQpjbCA8LSBtYWtlQ2x1c3RlcihtYyA8LSBnZXRPcHRpb24oImNsLmNvcmVzIiwgbnJjb3JlKSkNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkNCnNldC5zZWVkKDc3NykNCmxvZ2l0c21vdGUgPC0gdHJhaW4oYmsgfiAuLCBkYXRhID0gdHJhaW4sIG1ldGhvZCA9ICJnbG0iLA0KdHJDb250cm9sID0gYkN0cmwpDQpzdG9wQ2x1c3RlcihjbCkNCmxvZ2l0c21vdGUkcmVzdWx0cyAlPiUNCiAga2FibGUoZGlnaXRzPTIpICU+JQ0Ka2FibGVfc3R5bGluZyhsYXRleF9vcHRpb25zID0gIkhPTERfcG9zaXRpb24iKQ0KYGBgDQoNCiMjIyMgUm9zZQ0KDQoNCmBgYHtyfQ0KYkN0cmwkc2FtcGxpbmcgPC0gInJvc2UiDQpucmNvcmUgPC0gNQ0KY2wgPC0gbWFrZUNsdXN0ZXIobWMgPC0gZ2V0T3B0aW9uKCJjbC5jb3JlcyIsIG5yY29yZSkpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQpzZXQuc2VlZCg3NzcpDQpsb2dpdHJvc2UgPC0gdHJhaW4oYmsgfiAuLCBkYXRhID0gdHJhaW4sIG1ldGhvZCA9ICJnbG0iLCB0ckNvbnRyb2wgPSBiQ3RybCkNCnN0b3BDbHVzdGVyKGNsKQ0KbG9naXRyb3NlJHJlc3VsdHMgJT4lDQogIGthYmxlKGRpZ2l0cz0yKSAlPiUNCmthYmxlX3N0eWxpbmcobGF0ZXhfb3B0aW9ucyA9ICJIT0xEX3Bvc2l0aW9uIikNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KUHJlZCA8LSBwcmVkaWN0KGxvZ2l0c21vdGUxLCBuZXdkYXRhID10ZXN0KQ0KY29uZnVzbG9nc21vdGUxPC1jYXJldDo6Y29uZnVzaW9uTWF0cml4KHRhYmxlKFByZWQsIHRlc3QkYmspLCBwb3NpdGl2ZT0iWWVzIiwgbW9kZSA9ICJldmVyeXRoaW5nIikNCmNvbmZ1c2xvZ3Ntb3RlMQ0KYGBgDQoNCiMjIyMgRG93bi1zYW1wbGluZw0KDQoNCmBgYHtyfQ0KYkN0cmwkc2FtcGxpbmcgPC0gImRvd24iDQpucmNvcmUgPC0gNQ0KY2wgPC0gbWFrZUNsdXN0ZXIobWMgPC0gZ2V0T3B0aW9uKCJjbC5jb3JlcyIsIG5yY29yZSkpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQpzZXQuc2VlZCg3NzcpDQpsb2dpdGRvd24gPC0gdHJhaW4oYmsgfiAuLCBkYXRhID0gdHJhaW4sIG1ldGhvZCA9ICJnbG0iLCANCiAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBiQ3RybCkNCnN0b3BDbHVzdGVyKGNsKQ0KDQpsb2dpdGRvd24kcmVzdWx0cyAlPiUNCiAga2FibGUoZGlnaXRzPTIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGxhdGV4X29wdGlvbnMgPSAiSE9MRF9wb3NpdGlvbiIpDQpgYGANCg0KDQojIyMjIE92ZXItc2FtcGxpbmcNCmBgYHtyfQ0KYkN0cmwkc2FtcGxpbmcgPC0gInVwIg0KbnJjb3JlIDwtIDUNCmNsIDwtIG1ha2VDbHVzdGVyKG1jIDwtIGdldE9wdGlvbigiY2wuY29yZXMiLCBucmNvcmUpKQ0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0Kc2V0LnNlZWQoNzc3KQ0KbG9naXRkb3duIDwtIHRyYWluKGJrIH4gLiwgZGF0YSA9IHRyYWluLCBtZXRob2QgPSAiZ2xtIiwgDQogICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gYkN0cmwpDQpzdG9wQ2x1c3RlcihjbCkNCg0KbG9naXR1cCRyZXN1bHRzICU+JQ0KICBrYWJsZShkaWdpdHM9MikgJT4lDQogIGthYmxlX3N0eWxpbmcobGF0ZXhfb3B0aW9ucyA9ICJIT0xEX3Bvc2l0aW9uIikNCmBgYA0KDQoNCg0KDQojIyMjIFNtb3RlDQoNCiMjIyMgUm9zZQ0KDQojIyMjIFVwLXNhbXBsaW5nDQoNCiMjIyMgRG93bi1zYW1wbGluZw0KDQoNCiMgQ29tcGFyYWlzb24gZGVzIHLDqXN1bHRhdHMNCg0KIyBDb25jbHVzaW9uIGV0IGRpc2N1c3Npb24NCg0KIyBBTk5FWEVTICA6ICANCg0KVk9JUiBQT1VSIEZBSVJFIFZSQUkgQU5ORVhFUyBTVVIgUg0KU2NyaXB0IHV0aWxpc8OpIHBvdXIgbGEgZ8OpbsOpcmF0aW9uIGRlcyBncmFwaGlxdWVzIExIQVJCQQ0KDQpgYGB7ciwgd2FybmluZz1GYWxzZX0NCmNhdChyZWFkTGluZXMoJ1Byb2pldC5yc3QnKSwgc2VwID0gJ1xuJykNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=